package com.bauer.java.doc.excel;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @Author ：rui.wei
 * @Date ：Created in 14:45 2019/7/18
 * @Description：
 */
public class ExcelUtils {


    public static void main(String[] args) {
        File file = new File("C:\\Users\\Administrator\\Desktop\\导入模板.xlsx");
        try {
            getListData(new FileInputStream(file), com.bauer.java.doc.excel.Field.class);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析excel中数据生成List数据 注意点： 1、模板设置时单元格格式统一设置为 文本 2、只支持每行格式保持一致的excel
     *
     * @param inputStream 输入流
     * @param tClass 的对象类型信息
     * @param <T> 泛型
     * @return 对象list
     */
    public static <T> List<T> getListData(InputStream inputStream, Class<T> tClass) {
        List<T> resultList = new ArrayList<>();
        Workbook workbook = null;
        try {
            workbook = WorkbookFactory.create(inputStream);
            //只支持第一个sheet页
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rowIterator = sheet.rowIterator();

            Field[] fields = tClass.getDeclaredFields();

            List<FiledContext> filedContextList = new ArrayList<>();

            //获取行头
            Row headRow = rowIterator.next();
            Iterator<Cell> iterator = headRow.cellIterator();
            while (iterator.hasNext()) {
                Cell cell = iterator.next();
                for (Field field : fields) {
                    ExcelHeader excelHeader = field.getAnnotation(ExcelHeader.class);
                    if (excelHeader != null && excelHeader.name().equals(cell.getStringCellValue())) {
                        FiledContext filedContext = new FiledContext(field, cell.getColumnIndex());
                        filedContext.setDataFormatPattern(excelHeader.dateFormat());
                        filedContextList.add(filedContext);
                    }
                }
            }

            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();
                T t = tClass.newInstance();
                for (FiledContext filedContext : filedContextList) {
                    Cell cell = row.getCell(filedContext.getColumnIndex());
                    invokeSetMethod(t, filedContext, cell);
                }
                resultList.add(t);
            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return resultList;
    }


    /**
     * 设置属性值
     *
     * @param object 数据对象
     * @param filedContext 字段上下文
     * @param cell 值
     */
    public static void invokeSetMethod(Object object, FiledContext filedContext, Cell cell) throws Exception {
        Field field = filedContext.getField();
        String cellStringValue = cell.getStringCellValue();
        Method method = getSetMethod(object.getClass(), field);

        //存在映射关系
        if (filedContext.enumMap != null) {
            cellStringValue = filedContext.enumMap.get(cellStringValue);
        }

        if (field.getType() == String.class) {
            method.invoke(object, cellStringValue);
        } else if (field.getType() == int.class) {
            method.invoke(object, new Integer(cellStringValue));
        } else if (field.getType() == double.class || field.getType() == Double.class) {
            method.invoke(object, new Double(cellStringValue));
        } else if (field.getType() == float.class || field.getType() == Float.class) {
            method.invoke(object, new Float(cellStringValue));
        } else if (field.getType() == long.class || field.getType() == Long.class) {
            method.invoke(object, new Long(cellStringValue));
        } else if (field.getType() == Date.class) {
            SimpleDateFormat sdf = new SimpleDateFormat(filedContext.dataFormatPattern);
            method.invoke(object, sdf.parse(cellStringValue));
        }


    }

    public static Method getSetMethod(Class tClass, Field field) throws NoSuchMethodException {
        String filedName = field.getName();
        String methodName = "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
        return tClass.getMethod(methodName, field.getType());
    }

    /**
     * 字段容器
     */
    static class FiledContext {


        private Field field;

        private int columnIndex;

        private String dataFormatPattern;

        private Map<String, String> enumMap;

        public FiledContext(Field field, int columnIndex) {
            this.field = field;
            this.columnIndex = columnIndex;
        }

        public Field getField() {
            return field;
        }

        public void setField(Field field) {
            this.field = field;
        }

        public int getColumnIndex() {
            return columnIndex;
        }

        public void setColumnIndex(int columnIndex) {
            this.columnIndex = columnIndex;
        }

        public String getDataFormatPattern() {
            return dataFormatPattern;
        }

        public void setDataFormatPattern(String dataFormatPattern) {
            this.dataFormatPattern = dataFormatPattern;
        }

        public void initMapInfo(String string) {
            if (string == null) {
                return;
            }

            String[] singleKv = string.split("|");
            if (singleKv.length == 0) {
                return;
            }

            enumMap = new HashMap<>();
            for (String kv : singleKv) {
                String[] entry = kv.split("=");
                if (entry.length == 2) {
                    enumMap.put(entry[0], entry[1]);
                }
            }

            if (enumMap.isEmpty()) {
                enumMap = null;
            }
        }
    }
}
